import re
import time
import datetime
import logging
import requests
import click

from .misc import add_exchange_abbrev, send_mail_to, is_during_trade_time
from . import root
from traceback import format_exc
from typing import List

logger = logging.getLogger(__name__)

def prices_of_stocks(stockids: List[str]):
    stock_pattern = re.compile(r'"(.+?)"')
    prepared_stockids = [add_exchange_abbrev(sid) for sid in stockids]
    joind_stockids = ",".join(prepared_stockids)
    timestamp = int(datetime.datetime.now().timestamp() * 1000)
    response = requests.get(f"https://hq.sinajs.cn/etag.php?_={str(timestamp)}&list={joind_stockids}",
        headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0"})
    if response.ok:
        logger.info(f"request ok with stock list {prepared_stockids}")
        content = response.content.decode("gbk")
        stock_names = []
        stock_prices = []
        for row in stock_pattern.finditer(content):
            items = row[1].split(",")
            stock_name = items[0]
            stock_price = float(items[3])
            stock_names.append(stock_name)
            stock_prices.append(stock_price)
        logger.info(f"parsed stock prices list {list(zip(stock_names, stock_prices))}")
        return stock_prices
    else:
        logger.error(f"request failed with stock list [{prepared_stockids}], status_code={response.status_code}, headers='{response.headers}', body='{response.content}'")
        return []


@root.command()
@click.pass_context
def fetch(ctx):
    config = ctx.obj['config']
    try:
        ids = [config['stocks'][name]['id'] for name in config['stocks']]
        prices_of_stocks(ids)
    except Exception as e:
        logger.fatal(format_exc())


def watch_callback(receivers, host, port, username, password, names, ids, price_ranges):
    now = datetime.datetime.now()
    new_prices = prices_of_stocks(ids)
    messages = []
    for stock, sid, price_range, price in zip(names, ids, price_ranges, new_prices):
        from_, to = min(price_range), max(price_range)
        if price < from_ or price > to:
            msg = f"{stock}（{sid}）超出了持有范围 [{from_},{to}] ，目前价格是 {price}，查询时间 {now!s}"
            messages.append(msg)
            logger.warn(msg)
    if len(messages) > 0:
        send_mail_to(receivers, "持有价格超出警告", "\n".join(messages), host, port, username, password)


@root.command()
@click.pass_context
def watch(ctx):
    config = ctx.obj['config']
    try:
        names = [name for name in config['stocks']]
        ids = [config['stocks'][name]['id'] for name in config['stocks']]
        price_ranges = [config['stocks'][name]['keep_price_range'] for name in config['stocks']]
        cb = lambda : watch_callback(config['receivers'], config['sender']['host'], config['sender']['port'], config['sender']['username'], config['sender']['password'], names, ids, price_ranges)
        while True:
            if is_during_trade_time():
                cb()
            time.sleep(60*10)
    except Exception as e:
        logger.fatal(format_exc())
    

@root.command()
@click.pass_context
def oneshot(ctx):
    config = ctx.obj['config']
    try:
        names = [name for name in config['stocks']]
        ids = [config['stocks'][name]['id'] for name in config['stocks']]
        price_ranges = [config['stocks'][name]['keep_price_range'] for name in config['stocks']]
        cb = lambda : watch_callback(config['receivers'], config['sender']['host'], config['sender']['port'], config['sender']['username'], config['sender']['password'], names, ids, price_ranges)
        cb()
    except Exception as e:
        logger.fatal(format_exc())
